home *** CD-ROM | disk | FTP | other *** search
/ HTBasic 9.3 / HTBasic 9.3.iso / SICL / data1.cab / sicl32 / c / samples / scope / scope.c < prev    next >
Encoding:
C/C++ Source or Header  |  2001-03-02  |  18.2 KB  |  607 lines

  1. ////////////////////////////////////////////////////////////////////////////////
  2. //
  3. // Filename: scope.c
  4. //
  5. // This program demonstrates the Standard Instrument Control
  6. // Library within a Windows Program.
  7. //
  8. // The program uses a new addressing feature for the SICL iopen()
  9. // function called "symbolic naming".  See to the Read Me First file
  10. // for an explanation of this feature.
  11. //
  12. // This program requires two devices to run:
  13. //      54601A digitizing oscilloscope (or compatible scope)
  14. //      a printer capable of printing in HP RASTER GRAPHICS STANDARD
  15. //      (e.g. ThinkJet printers)
  16. // An optional multimeter such as an Agilent 34401A may also be connected.
  17. //
  18. // The windows application contains an "Action" menu with four
  19. // commands:
  20. //    "get_voltage"    Take voltage rading from multimeter
  21. //    "perform_meas"   Program scope to make measurement, then upload results
  22. //    "show_header"    Show scope settings
  23. //    "print_disp"     Command scope to print its display.
  24. //
  25. // The commands that are sent to the scope are device dependent, and
  26. // are found in the manual for the scope.
  27. //
  28. // This program is designed to illustrate several individual SICL
  29. // commands and is not meant to be an example of a robust Windows
  30. // application.
  31. ////////////////////////////////////////////////////////////////////////////////
  32.  
  33. #include <string.h>        // strlen()
  34. #include <stdlib.h>        // exit()
  35. #include <stdio.h>         // sprintf()
  36. #include <windows.h>       // Windows API declarations
  37. #include "sicl.h"          // Standard Instrument Control Library routines
  38. #include "scope.h"         // message defines
  39.  
  40. // function prototypes
  41. long FAR PASCAL _export WndProc(HWND hWnd, unsigned iMessage, unsigned wParam, long lParam);
  42. void enable_io_menu_items(BOOL);
  43. void SICLCALLBACK my_err_handler(INST, int);
  44. void SICLCALLBACK my_srq_handler(INST);
  45. void init_scope_io (void);
  46. void close_scope (void);
  47. void get_data (INST);
  48. void get_voltage (void);
  49. void show_scope_settings (void);
  50. void print_disp (INST);
  51.  
  52. // defines
  53. #define R_ELEMENTS       5000
  54. #define TIMEOUT          5000     // 5 second timeout value (in ms)
  55. #define MAX_LINES        20       // max number of lines printed on screen
  56.  
  57. // global data
  58. HWND   hWnd;                      // application window handle
  59. HWND   hInst;
  60. INST   scope;                     // session id for scope
  61. int    readings [R_ELEMENTS];
  62. int    num_lines=0;               // number of text lines to output
  63. int    ioerror = 0;
  64. unsigned char scopeidn[50];
  65. unsigned char probe[8];
  66. float  pre [20];
  67. char   text_buf[MAX_LINES][80];   // used for displaying text output
  68.  
  69. /////////////////////////////////////////////////////////////////////
  70. //
  71. // WinMain:
  72. //
  73. // Parameters:
  74. //   hInstance - number that uniquely identifies this program
  75. //   hPrevInstance - handle of previous instance of this program
  76. //   lpszCmdLine - pointer to command line argument string
  77. //   nCmdShow - indicates how the window will be displayed
  78. //
  79. // Description:
  80. //   This routine implements the Windows event loop for the application.
  81. //
  82. /////////////////////////////////////////////////////////////////////
  83. int PASCAL WinMain (HANDLE hInstance, HANDLE hPrevInstance, LPSTR lpszCmdLine,
  84.                     int nCmdShow)
  85. {
  86.     static char szAppName[] = "scope";
  87.     MSG            msg;
  88.     WNDCLASS    wndclass;
  89.     lpszCmdLine = lpszCmdLine;
  90.  
  91.     if (!hPrevInstance) {
  92.         wndclass.style          = CS_HREDRAW | CS_VREDRAW;
  93.         wndclass.lpfnWndProc    = WndProc;
  94.         wndclass.cbClsExtra     = 0;
  95.         wndclass.cbWndExtra     = 0;
  96.         wndclass.hInstance      = hInstance;
  97.         wndclass.hIcon          = LoadIcon (hInstance, "scopeicon");
  98.         wndclass.hCursor        = LoadCursor ((HMODULE)NULL, IDC_ARROW);
  99.         wndclass.hbrBackground  = GetStockObject (WHITE_BRUSH);
  100.         wndclass.lpszMenuName   = "scopemenu";
  101.         wndclass.lpszClassName  = szAppName;
  102.  
  103.         if (!RegisterClass (&wndclass))
  104.             return FALSE;
  105.     }
  106.  
  107.  
  108.     hWnd = CreateWindow (szAppName,
  109.                          "scope",
  110.                          WS_OVERLAPPEDWINDOW,
  111.                          CW_USEDEFAULT,
  112.                          CW_USEDEFAULT,
  113.                          800,
  114.                          400,
  115.                          (HWND)NULL,
  116.                          (HMENU)NULL,
  117.                          hInstance,
  118.                          NULL);
  119.  
  120.     ShowWindow (hWnd, nCmdShow);
  121.  
  122.     UpdateWindow (hWnd);
  123.  
  124.     init_scope_io();
  125.  
  126.     while(GetMessage (&msg, (HWND)NULL, 0, 0)) {
  127.         TranslateMessage (&msg);
  128.         DispatchMessage (&msg);
  129.     }
  130.  
  131.     return msg.wParam;
  132. }
  133.  
  134. /////////////////////////////////////////////////////////////////////
  135. //
  136. // WndProc:
  137. //
  138. // Parameters:
  139. //   hWnd - identifies the window receiving the message
  140. //   iMessage - identifies the message
  141. //   wParam - provides more information about the message
  142. //   lParam - provides more information about the message
  143. //
  144. // Description:
  145. //   The following routine processes window messages.
  146. //
  147. /////////////////////////////////////////////////////////////////////
  148. long FAR PASCAL _export WndProc (HWND hWnd, unsigned iMessage, unsigned wParam, long lParam)
  149. {
  150.     static int      xChar;
  151.     static int      yChar;
  152.     HDC             hDC;
  153.     PAINTSTRUCT     ps;
  154.     TEXTMETRIC      tm;
  155.     int             i;
  156.  
  157.     switch (iMessage) {
  158.         case WM_CREATE:
  159.             hInst = ((LPCREATESTRUCT) lParam) -> hInstance;
  160.  
  161.             hDC = GetDC (hWnd);
  162.             GetTextMetrics (hDC, &tm);
  163.             xChar = tm.tmAveCharWidth;
  164.             yChar = tm.tmHeight;
  165.             ReleaseDC (hWnd, hDC);
  166.  
  167.             num_lines = 0;  // set message output to top of window
  168.  
  169.             break;
  170.  
  171.         case WM_DESTROY:
  172.  
  173.             close_scope();
  174.  
  175.             PostQuitMessage (0);
  176.             break;
  177.  
  178.         case WM_COMMAND:
  179.             if (!LOWORD (lParam)) {
  180.                 switch (wParam) {
  181.                     case SCOPE_EXIT:
  182.                         SendMessage (hWnd, WM_CLOSE, 0, 0L);
  183.                         break;
  184.  
  185.                     case SCOPE_READ_VOLT:
  186.                         get_voltage();
  187.                         break;
  188.  
  189.                     case SCOPE_GET_DATA:
  190.                         get_data(scope);
  191.                         break;
  192.  
  193.                     case SCOPE_HEADER:
  194.                         show_scope_settings();
  195.                         break;
  196.  
  197.                     case SCOPE_PRINT:
  198.                         print_disp(scope);
  199.                         break;
  200.  
  201.                     default:
  202.                         return DefWindowProc (hWnd, iMessage, wParam, lParam);
  203.                 }
  204.             } else {
  205.                 return DefWindowProc (hWnd, iMessage, wParam, lParam);
  206.             }
  207.  
  208.             break;
  209.  
  210.         case WM_PAINT:
  211.             hDC = BeginPaint (hWnd, &ps);
  212.  
  213.             for (i = 0; i <num_lines; i++) {
  214.                 TextOut(hDC, xChar, yChar * i, text_buf[i], strlen(text_buf[i]));
  215.             }
  216.  
  217.             EndPaint (hWnd, &ps);
  218.             break;
  219.  
  220.         default:
  221.             return DefWindowProc (hWnd, iMessage, wParam, lParam);
  222.     }
  223.     return 0L;
  224. }
  225.  
  226. /////////////////////////////////////////////////////////////////////
  227. //
  228. // enable_io_menu_items:
  229. //
  230. // Parameters:
  231. //   enable_menus - TRUE to enable menus items, FALSE to disable
  232. //
  233. // Description:
  234. //   This routine is used to disable I/O menu selections while
  235. //   calls to the Standard Instrument Control Library are in
  236. //   progress.
  237. //
  238. /////////////////////////////////////////////////////////////////////
  239. void enable_io_menu_items(BOOL enable_menus)
  240. {
  241.     HMENU hMenu;
  242.     unsigned  io_menu_state;
  243.  
  244.     hMenu = GetMenu(hWnd);
  245.  
  246.     if (enable_menus && !ioerror)
  247.         io_menu_state = MF_ENABLED;
  248.     else
  249.         io_menu_state = MF_GRAYED;
  250.  
  251.     EnableMenuItem(hMenu, SCOPE_READ_VOLT, io_menu_state);
  252.     EnableMenuItem(hMenu, SCOPE_GET_DATA, io_menu_state);
  253.     EnableMenuItem(hMenu, SCOPE_PRINT, io_menu_state);
  254.  
  255. }
  256.  
  257.  
  258. /////////////////////////////////////////////////////////////////////
  259. //
  260. // my_err_handler:
  261. //
  262. // Parameters:
  263. //   id - identifies the I/O session in which an error occured.
  264. //   err - the error that occured
  265. //
  266. // Description:
  267. //   This routine is installed with ionerror() and is called when an
  268. //   error occurs in a call to the Standard Instrument Control Library.
  269. //   It will cause a message to be written to the application
  270. //   window and will prevent any further actions.
  271. //
  272. /////////////////////////////////////////////////////////////////////
  273. void SICLCALLBACK my_err_handler(INST id, int error)
  274. {
  275.     HMENU hMenu;
  276.  
  277.     sprintf(text_buf[num_lines++],
  278.              "session id=%d, error = %d:%s", id, error, igeterrstr(error));
  279.     sprintf(text_buf[num_lines++], "Select `File | Exit' to exit program!");
  280.  
  281.     InvalidateRect(hWnd, NULL, TRUE);
  282.  
  283.     // If error is from scope, disable I/O actions by graying out menu picks.
  284.     if (id == scope) {
  285.         hMenu = GetMenu(hWnd);
  286.  
  287.         EnableMenuItem(hMenu, SCOPE_READ_VOLT, MF_GRAYED);
  288.         EnableMenuItem(hMenu, SCOPE_GET_DATA, MF_GRAYED);
  289.         EnableMenuItem(hMenu, SCOPE_HEADER, MF_GRAYED);
  290.         EnableMenuItem(hMenu, SCOPE_PRINT, MF_GRAYED);
  291.  
  292.         // set flag indicating that a scope error occurred.
  293.         ioerror = 1;
  294.     }
  295.  
  296.     // set flag indicating that a scope error occurred.
  297.     ioerror = 1;
  298. }
  299.  
  300. /////////////////////////////////////////////////////////////////////
  301. //
  302. // my_srq_handler:
  303. //
  304. // Parameters:
  305. //   id - identifies the I/O session for the SRQ.
  306. //
  307. // Description:
  308. //   This routine is called when an SRQ is generated by a device.
  309. //
  310. /////////////////////////////////////////////////////////////////////
  311. void SICLCALLBACK my_srq_handler(INST id)
  312. {
  313.     unsigned char status;
  314.  
  315.     // make sure it was the scope requesting service
  316.     ireadstb(id,&status);
  317.  
  318.     if (status &= 64) {
  319.         // clear the status byte so the scope can assert SRQ again if needed.
  320.         iprintf(id,"*CLS\n");
  321.  
  322.         sprintf(text_buf[num_lines++],
  323.                  "SRQ received!, stat=0x%x",status);
  324.     } else {
  325.         sprintf(text_buf[num_lines++],
  326.                  "SRQ received, but not from the scope");
  327.     }
  328.     InvalidateRect(hWnd, NULL, TRUE);
  329. }
  330.  
  331. /////////////////////////////////////////////////////////////////////
  332. //
  333. // init_scope_io:
  334. //
  335. // Parameters:
  336. //   none
  337. //
  338. // Description:
  339. //   This routine installs a SICL error handler, opens a device
  340. //   session for the scope and puts the scope in a known state.
  341. //
  342. /////////////////////////////////////////////////////////////////////
  343. void init_scope_io(void)
  344. {
  345.     // install custom error handler
  346.     ionerror(my_err_handler);
  347.  
  348.     // open a device session to the scope
  349.     scope = iopen("scope");
  350.  
  351.     if (scope == 0) {
  352.         sprintf(text_buf[num_lines++],"Oscilloscope iopen failed!");
  353.     } else {
  354.         sprintf(text_buf[num_lines++],"Oscilloscope session initialized!");
  355.         // set a timeout value for the session
  356.         itimeout(scope, TIMEOUT);
  357.  
  358.         // put the scope in a known state
  359.         iclear(scope);
  360.         iremote(scope);
  361.     }
  362.     InvalidateRect(hWnd, NULL, TRUE);  // print output
  363. }
  364.  
  365. /////////////////////////////////////////////////////////////////////
  366. //
  367. // close_scope:
  368. //
  369. // Parameters:
  370. //   none
  371. //
  372. // Description:
  373. //   This routine cleans up, closes the scope session and calls
  374. //   _siclcleanup.
  375. //
  376. /////////////////////////////////////////////////////////////////////
  377. void close_scope(void)
  378. {
  379.     // give local control back to the scope
  380.     ilocal(scope);
  381.  
  382.     // close the session
  383.     iclose(scope);
  384.  
  385.     // Call _siclcleanup before exiting to release resources allocated
  386.     // by SICL for this application (required for Windows 3.1).
  387.     _siclcleanup();
  388. }
  389.  
  390.  
  391. /////////////////////////////////////////////////////////////////////
  392. //
  393. // get_voltage:
  394. //
  395. // Parameters:
  396. //   none
  397. //
  398. // Description:
  399. //   The following routine gets voltage readings from the Digital
  400. //   MultiMeter specified by the symbolic name "dmm" in SICL.INI
  401. //
  402. /////////////////////////////////////////////////////////////////////
  403. void get_voltage(void)
  404. {
  405.     INST dmm;
  406.     double voltage;
  407.     unsigned char cmd[50];
  408.  
  409.     enable_io_menu_items(FALSE);  // do this before making sicl calls
  410.  
  411.     dmm = iopen("dmm");
  412.     itimeout(dmm, 500);
  413.  
  414.     // put the meter in a known state and get its IDN string.
  415.     iprintf(dmm,"*RST;*CLS\n");
  416.     ipromptf(dmm,"*IDN?\n","%s",cmd);
  417.  
  418.     sprintf(text_buf[num_lines++],"DMM is %s",cmd);
  419.  
  420.     // make a DC voltage reading and get the result.
  421.     iprintf(dmm,"measure:volt:dc?\n");
  422.     iscanf(dmm,"%lf",&voltage);
  423.  
  424.     sprintf(text_buf[num_lines++],"  Current voltage: %lf V",voltage);
  425.  
  426.     // close the session
  427.     iclose(dmm);
  428.  
  429.     InvalidateRect(hWnd, NULL, TRUE);  // print output
  430.  
  431.     enable_io_menu_items(TRUE);  // do this after making all sicl calls
  432. }
  433.  
  434. /////////////////////////////////////////////////////////////////////
  435. //
  436. // get_data:
  437. //
  438. // Parameters:
  439. //   INST id for the scope device session.
  440. //
  441. // Description:
  442. //   The following routine gets settings and waveform data from the
  443. //   scope.  The device is locked during the measurement to prevent
  444. //   outside access.
  445. //
  446. /////////////////////////////////////////////////////////////////////
  447. void get_data (INST id)
  448. {
  449.     long   elements;
  450.  
  451.     enable_io_menu_items(FALSE);  // do this before making sicl calls
  452.  
  453.     // lock the device to prevent access from other applications
  454.     ilock(scope);
  455.  
  456.     // initialize scope
  457.     iprintf(id,"*RST\n");
  458.  
  459.     // retrieve the scope's ID string
  460.     ipromptf(id,"*IDN?\n","%s",scopeidn);
  461.  
  462.     // setup up the waveform source
  463.  
  464.     iprintf(id,":autoscale\n");
  465.     iprintf(id,":waveform:format word\n");
  466.  
  467.     // input waveform preamble to controller
  468.  
  469.     iprintf(id,":digitize channel1\n");
  470.     iprintf(id,":waveform:preamble?\n");
  471.  
  472.     // read the scope preamble - 20 comma-separated values.
  473.     iscanf(id,"%,20f\n",pre);
  474.  
  475.     // command scope to send the data
  476.     iprintf(id,":waveform:data?\n");
  477.  
  478.     // enter the data
  479.     elements = R_ELEMENTS;
  480.     iscanf(id,"%#wb\n",&elements,readings);
  481.  
  482.     if ( elements == R_ELEMENTS ) {
  483.         sprintf (text_buf[num_lines++],"Readings buffer full: May not have received all points");
  484.         InvalidateRect(hWnd, NULL, TRUE);
  485.     }
  486.  
  487.     // Get probe attenuation
  488.     ipromptf(id,":chan1:probe?\n","%s",probe);
  489.  
  490.     // release the scope for use by others
  491.     iunlock(scope);
  492.  
  493.     sprintf(text_buf[num_lines++]," Oscilloscope waveform upload complete!");
  494.     InvalidateRect(hWnd, NULL, TRUE);  // print output
  495.  
  496.     enable_io_menu_items(TRUE);  // do this after making all sicl calls
  497. }
  498.  
  499. /////////////////////////////////////////////////////////////////////
  500. //
  501. // show_scope_settings:
  502. //
  503. // Parameters:
  504. //   none
  505. //
  506. // Description:
  507. //   This routine formats and prints the settings of the scope read
  508. //   in the get_data routine.  It does no I/O.
  509. //
  510. /////////////////////////////////////////////////////////////////////
  511. void show_scope_settings (void)
  512. {
  513.     float vdiv;
  514.     float off;
  515.     float sdiv;
  516.     float delay;
  517.  
  518.     num_lines = 0;  // set message output to top of window
  519.  
  520.     vdiv  = 32 * pre [7];
  521.     off   = (128 - pre [9]) * pre [7] + pre [8];
  522.     sdiv  = pre [2] * pre [4] / 10;
  523.     delay = (pre [2] / 2 - pre [6]) * pre [4] + pre [5];
  524.  
  525.     //    print the statistics about the data
  526.     //
  527.     sprintf (text_buf[num_lines++],"Oscilloscope ID:  %s", scopeidn);
  528.     sprintf (text_buf[num_lines++]," ------  Current Channel 1 Settings  ------");
  529.     sprintf (text_buf[num_lines++],"      Volts/Div = %f V", vdiv);
  530.     sprintf (text_buf[num_lines++],"         Offset = %f V", off);
  531.     sprintf (text_buf[num_lines++],"          Probe = %s"    , probe);
  532.     sprintf (text_buf[num_lines++],"          S/Div = %f S", sdiv);
  533.     sprintf (text_buf[num_lines++],"          Delay = %f S", delay);
  534.     sprintf (text_buf[num_lines++]," ");
  535.     InvalidateRect(hWnd, NULL, TRUE);
  536. }
  537.  
  538. /////////////////////////////////////////////////////////////////////
  539. //
  540. // print_disp:
  541. //
  542. // Parameters:
  543. //   INST id for the scope device session.
  544. //
  545. // Description:
  546. //   Commands the scope to print it's display and send SRQ when
  547. //   complete.  The iwaithdlr function is used to suspend operation
  548. //   until the SRQ is received.
  549. //
  550. /////////////////////////////////////////////////////////////////////
  551. void print_disp (INST id)
  552. {
  553.     INST gpibintf;
  554.     unsigned char cmd[16];
  555.     int length;
  556.  
  557.     enable_io_menu_items(FALSE);  // do this before making all sicl calls
  558.     num_lines = 0;  // set message output to top of window
  559.  
  560.     // get the interface session for this device
  561.     gpibintf = igetintfsess(id);
  562.  
  563.     // disable interrupt events
  564.     iintroff();
  565.  
  566.     // install the SRQ handler
  567.     ionsrq(id,my_srq_handler);   // Not supported on Agilent 82335
  568.  
  569.     // tell the scope to SRQ on 'operation complete'
  570.     iprintf(id,"*CLS\n");
  571.     iprintf(id,"*SRE 32; *ESE 1\n");
  572.  
  573.     // tell the scope to print
  574.     iprintf(id,":print?; *OPC\n");
  575.  
  576.     // tell the scope to talk and printer to listen
  577.     //    the listen command is formed by adding 32 to the device address
  578.     //        of the device to be a listener
  579.     //    the talk command is formed by adding 64 to the device address of
  580.     //        the device to be a talker
  581.  
  582.     cmd[0] = (unsigned char)63;      // 63 is unlisten
  583.     cmd[1] = (unsigned char)(32+1);  // printer at addr 1, make it a listener
  584.     cmd[2] = (unsigned char)(64+7);  // scope at addr 7, make it a talker
  585.     cmd[3] = '\0';                    // terminate the string
  586.  
  587.     length = strlen (cmd);
  588.  
  589.     // Use GPIB specific commands to control the bus and interface
  590.     igpibsendcmd(gpibintf,cmd,length);
  591.     igpibatnctl(gpibintf,0);
  592.  
  593.     sprintf (text_buf[num_lines++],"Waiting for print to complete...");
  594.     InvalidateRect(hWnd, NULL, TRUE);
  595.  
  596.     // wait for SRQ  or 30 seconds before continuing.
  597.     iwaithdlr(30000L);
  598.  
  599.     // Re-enable interrupt events.
  600.     iintron();
  601.  
  602.     sprintf (text_buf[num_lines++],"Printing complete!");
  603.     InvalidateRect(hWnd, NULL, TRUE);
  604.  
  605.     enable_io_menu_items(TRUE);  // do this after making all sicl calls
  606. }
  607.